from django.shortcuts import render
from rest_framework import generics, mixins
from rest_framework.views import APIView
# from rest_framework.response import Response
from method.tools import Response
from rest_framework import status as status_code
from ars import serializers
from ac import models
from tb_menu.function.update_menu import updateMenu
from method import ars, tools, decorator
from method.db import ConnDB
from django.conf import settings

import json


class ProjectsView(generics.ListAPIView):
    """
    當獲取數據的格式為JSON時，中文會被轉碼為Unicode編碼
    """

    serializer_class = serializers.ProjectSerializer

    def get_queryset(self):
        return models.Project.objects.filter(status_id=200)

    @decorator.include_chinese
    def get(self, request, *args, **kwargs):
        app = request.GET.get("app", None)
        if app:
            self.queryset = models.Project.objects.filter(status_id=200, have_app=True)
        else:
            self.queryset = self.get_queryset()
        result = []
        for query in self.queryset:
            data = serializers.ProjectSerializer(query).data
            data["modules"] = query.get_modules()
            result.append(data)
        return result


class CheckUserView(generics.CreateAPIView):
    """
    GET: 提交用户名(username)，验证工号的有效性，如是否存在，是否在有效期\n
    POST: 提交用戶名(username)和密碼(password)，返回驗證結果，結果不包含用戶信息
    """

    def get_serializer_class(self):
        return serializers.CheckSerializer

    def get(self, request):
        username = request.GET.get("username", None)

        if not username:
            return Response({"status": "False",
                             "message": "Please enter the corresponding parameter username or password!"},
                            status=status_code.HTTP_200_OK)
        else:
            user_obj = models.MyUser.objects.filter(username__iexact=username)

        if not user_obj:
            return Response({"status": "False",
                             "message": "User: '%s' does not exist!" % username},
                            status=status_code.HTTP_200_OK)
        elif user_obj[0].is_active is False or user_obj[0].status_id != 200:
            return Response({"status": "False",
                             "message": "User: '%s' does not exist!" % username},
                            status=status_code.HTTP_200_OK)
        else:
            return Response({"status": "True",
                             "message": "Account is normal!"},
                            status=status_code.HTTP_200_OK)

    def post(self, request, *args, **kwargs):
        # username = request.POST.get("username", None)
        # password = request.POST.get("password", None)
        data = tools.is_valid(request, "POST", "username", "password")
        if not isinstance(data, dict):
            return data

        if not data["username"] or not data["password"]:
            return Response({"status": "False", "message": "Work number or password cannot be empty!"})

        user_obj = models.MyUser.objects.filter(username__iexact=data["username"])
        if not user_obj:
            msg = "Users '%s' does not exist!" % data["username"]
            return Response({"status": "False", "message": msg})
        else:
            user_obj = user_obj[0]

        if user_obj.check_password(data["password"]):
            return Response({
                "status": "True", "message": ""
            })
        else:
            return Response({
                "status": "False", "message": "wrong password!"
            })


class ProjectRoleView(APIView):
    """
    获取Project所有的角色
    """
    @decorator.include_chinese
    def get(self, request, *args, **kwargs):
        PID = request.GET.get("PID", None)

        if not PID:
            # return Response({"status": "False", "message": "Please input PID!"},
            #                 status=status_code.HTTP_200_OK)
            return {"status": "False", "message": "Please input PID!"}
        else:
            role_list = models.Role.objects.filter(project__PID=PID)
            data = [{'id': i.id, 'name': i.role_name} for i in role_list]
            # return Response({"status": "True", "role": data},
            #                 status=status_code.HTTP_200_OK)
            if not data:
                return {"status": "False", "message": "Role is null!"}
            return {"status": "True", "role": data}


# class FunctionView(generics.CreateAPIView):
#     """
#     为Project添加功能API，需要提供两个参数：PID(Project ID)， function(一个功能的字典，格式参照输入框下面的示例)
#     """
#     def get_serializer_class(self):
#         return serializers.FunctionSerializer
#
#     def get(self, request, *args, **kwargs):
#         return Response({"status": "False", "message": "Please input PID and function"},
#                         status=status_code.HTTP_200_OK)
#
#     def post(self, request, *args, **kwargs):
#         PID = request.POST.get("PID", None)
#         function = request.POST.get("function", None)
#
#         # 检查用户的输入有效性
#         if not PID and function:
#             return Response({
#                 "status": "False", "message": "function info cannot be empty!"
#             }, status=status_code.HTTP_200_OK)
#         f = tools.Formatting(function)
#         function = f.__format__()
#         function = eval(function)
#
#         func = ars.Function()
#         try:
#             s, result = func.create_function(PID, function)
#         except ValueError as error:
#             return Response({"status": "False", "message": str(error)})
#
#         # return Response({"status": str(s), "message": result})


class ChildFunctionView(generics.ListAPIView):
    """
    接收一個GET參數：function(值應為function ID)
    """

    def get_serializer_class(self):
        return serializers.ChildFunctionSerializer

    def get_queryset(self):
        pass

    @decorator.include_chinese
    def get(self, request, *args, **kwargs):
        result = tools.is_valid(request, "GET", func_id="", tp="")
        if not isinstance(result, dict):
            return result.data

        if result["tp"] == "child":
            query = models.Function.objects.filter(pk=result["func_id"])
            if query:
                return serializers.ChildFunctionSerializer(query[0].get_child(), many=True).data
            else:
                return {"status": "False", "message": "function ID error!"}
        elif result["tp"] == "all":
            f = ars.ChildFuncAll(result["func_id"])
            query = f.get_child()
            if query:
                return serializers.ChildFunctionSerializer(query, many=True).data
            else:
                return {"status": "False", "message": "function ID error!"}


def home(request):
    # obj = AddRoleForm()
    return render(request, template_name='framework/inline/input.html')


class RolesView(generics.ListCreateAPIView):
    """
    獲取所有Role的信息
    """
    def get_serializer_class(self):
        return serializers.RoleSerializer

    def get_queryset(self):
        return models.Role.objects.filter(is_active=True)       # 僅顯示所有有效的角色記錄

    def post(self, request, *args, **kwargs):
        try:
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            obj = models.Role.objects.filter(role_name=request.data["role_name"], is_active=False)
            if obj:     # 先检查用户提交的角色信息是否为曾被删除的数据，是则激活，不是就创建新角色
                obj[0].is_active = True
                obj[0].save()
                return Response(self.get_serializer(obj[0]).data, status=status_code.HTTP_200_OK)
            else:
                result = self.create(request, *args, **kwargs)
        except ValueError as e:
            result = Response({"message": str(e)}, status=status_code.HTTP_202_ACCEPTED)
        return result


class RoleView(mixins.RetrieveModelMixin,
               mixins.UpdateModelMixin,
               mixins.DestroyModelMixin,
               generics.ListAPIView):
    """
    根據URL中傳遞的ID值來獲取單條Role的信息，支持刪、改的操作
    """
    serializer_class = serializers.RoleSerializer
    queryset = models.Role.objects.all()

    def get(self, request, *args, **kwargs):
        self.queryset = self.get_object()
        self.queryset.func_list = list(models.RoleFunctionMap.objects.filter(role_id=kwargs["pk"]).\
                                       values_list("function_id", flat=True))
        self.queryset.save()
        return Response(serializers.RoleSerializer(self.queryset).data)

    def put(self, request, *args, **kwargs):
        data = tools.is_valid(request, "PUT", "func_list")
        if not isinstance(data, dict):
            return data

        if data["func_list"] != self.get_object().func_list:       # 在变更用户功能的时候不能更新其他内容
            try:
                obj = ars.Role(kwargs["pk"], data["func_list"])
                result = obj.update_role_function()

                # 当角色的功能发生变更时，通知所有与此角色相关的用户刷新菜单
                userID = self.get_object().UR_role.all().values_list("user_id", flat=True)
                updateMenu(userID)
                return Response({"status": "True", "msg": result})
            except Exception as error:
                return Response({"status": "False", "msg": str(error)})
        else:
            return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        # return self.destroy(request, *args, **kwargs)
        obj = self.get_object()
        obj.is_active = False                                       # 先把角色的状态标记为False
        obj.save()
        models.RoleFunctionMap.objects.filter(role_id=49276).values_list("function_id", )
        models.UserRoleMap.objects.filter(role=obj).delete()        # 接着把该角色的用户关联记录删除

        # 当角色的功能发生变更时，通知所有与此角色相关的用户刷新菜单
        userID = self.get_object().UR_role.all().values_list("user_id", flat=True)
        updateMenu(userID)
        return Response({"message": "Delete successfully!"}, status=status_code.HTTP_200_OK)


class UserRoleMapsView(mixins.RetrieveModelMixin,
                       generics.ListCreateAPIView):
    """
    獲取所有用戶和角色的綁定信息\n
    參數一：'user.id'是單個的數字類型（用戶ID）\n
    參數二：'role.id'是角色ID的數組類型，即使只有一個角色，也需要是數組
    """
    serializer_class = serializers.UserRoleMapSerializer
    queryset = models.UserRoleMap.objects.all().order_by("user_id")

    def get(self, request, *args, **kwargs):
        if request.GET.get("void", None):
            self.queryset = models.MyUser.objects.filter(UR_query_user=None)      # 查询所有没有角色的用户
            return Response(serializers.UT(self.queryset, many=True).data)
        else:
            # return super(UserRoleMapsView, self).get(request, *args, **kwargs)
            result = []

            db = ConnDB("SELECT user_id FROM tb_user_role_map GROUP BY user_id")
            user_tuple = db.action()            # 獲取所有有角色的用戶列表
            for pk in user_tuple:
                data = {}
                # 獲取所有的用戶名稱信息
                # db.set_sql("SELECT id, username, last_name FROM tb_user WHERE id=%d AND status_id = %s"
                #            % (pk[0], settings.STATUS_ACTIVE["USER"]))
                # data["user"] = db.action()

                user_obj = models.MyUser.objects.filter(pk=pk[0])
                if not user_obj:
                    continue
                else:
                    user_obj = user_obj[0]

                data["user"] = [[user_obj.pk, user_obj.username, user_obj.last_name, user_obj.duty.name]]
                for user_org in user_obj.UO_user.all():
                    data["user"][0].append(user_org.org.get_full_org())

                # 獲取單個用戶下的所有角色有哪些，返回元祖類型
                db.set_sql("SELECT id, role_name FROM tb_project_role "
                           "WHERE id in (SELECT role_id FROM tb_user_role_map WHERE user_id = %d)" % pk[0])
                data["role"] = db.action()

                result.append(data)
            return Response(result, status=status_code.HTTP_200_OK)

    def post(self, request, *args, **kwargs):
        data = tools.is_valid(request, "POST", "user.id", "role.id")
        if not isinstance(data, dict):
            return data

        data["role.id"] = eval(data["role.id"])
        if not isinstance(data["role.id"], list):
            data["role.id"] = [data["role.id"]]

        succeed, exist = [], []

        for rid in data["role.id"]:
            result, status = models.UserRoleMap.objects.get_or_create(
                                                                    user_id=data["user.id"],
                                                                    role_id=rid)
            if status:
                succeed.append(result.role.role_name)
            else:
                exist.append(result.role.role_name)
        return Response({"succeed": str(succeed), "exist": str(exist)},
                        status=status_code.HTTP_201_CREATED)
        # if status:
        #     return Response({"message": "Successfully added!"},
        #                     status=status_code.HTTP_201_CREATED)
        # else:
        #     return Response({"message": "The user already has this role!"},
        #                     status=status_code.HTTP_202_ACCEPTED)


class UserRoleMapView(mixins.RetrieveModelMixin,
                      mixins.UpdateModelMixin,
                      mixins.DestroyModelMixin,
                      generics.ListAPIView):
    """
    單條用戶和角色的綁定信息，支持刪、改的操作,URL後面的數字是<font color="#FF0000">用戶ID</font>\n
    參數一：'user.id'是單個的數字類型（用戶ID）\n
    參數二：'role.id'是角色ID的數組類型，即使只有一個角色，也需要是數組\n
    DELETE刪除操作表示刪除用戶的一條角色綁定關係
    """
    serializer_class = serializers.UserRoleMapSerializer
    queryset = models.UserRoleMap.objects.all()
    lookup_field = "pk"

    def get(self, request, *args, **kwargs):
        user_id = kwargs['pk']
        data = {}
        # return self.retrieve(request, *args, **kwargs)

        # 獲取用戶名稱信息
        db = ConnDB("SELECT id, username, last_name FROM tb_user WHERE id=%s" % user_id)
        data["user"] = db.action()

        # 獲取單個用戶下的所有角色有哪些，返回元祖類型
        db.set_sql(
            "SELECT id, role_name FROM tb_project_role "
                "WHERE id in (SELECT role_id FROM tb_user_role_map WHERE user_id = %s) "
                    "AND is_active = TRUE" % user_id)
        data["role"] = db.action()
        return Response(data, status=status_code.HTTP_200_OK)
        # return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        uid = request.data['user.id']
        rid = request.data['role.id']

        user_role = ars.UserRoleUpdate(uid, rid)
        return Response({"message": user_role.update_user_role()}, status=status_code.HTTP_200_OK)
        # pk = kwargs['pk']
        #
        # obj = models.UserRoleMap.objects.filter(pk=pk)[0]
        # if obj.user_id == uid and obj.role_id == rid:
        #     return Response(self.serializer_class(obj).data)
        # else:
        #     user = models.MyUser.objects.filter(pk=uid)
        #     role = models.Role.objects.filter(pk=rid)
        #     if not user:
        #         Response({"status": "False", "message": "User ID does not exist!"})
        #     elif not role:
        #         Response({"status": "False", "message": "Role ID does not exist!"})
        #
        #     obj.user = user[0]
        #     obj.role = role[0]
        #     obj.save(force_update=True, update_fields=('user', 'role'))

        # return Response({"message": user_role.update_user_role()}, status=status_code.HTTP_200_OK)
        # return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        # return self.destroy(request, *args, **kwargs)
        try:
            user_id = kwargs["pk"]
            models.UserRoleMap.objects.filter(user_id=user_id).delete()
            updateMenu(userID=user_id)              # 告诉系统，这个用户的菜单被更新了
            return Response({"status": "True", "message": "The roles have been deleted!"},
                            status=status_code.HTTP_200_OK)
        except Exception as error:
            return Response({"status": "False", "message": str(error)})


class FunctionsView(mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.ListCreateAPIView):
    """
    獲取所有的功能信息
    """
    queryset = models.Function.objects.all()

    def get_serializer_class(self):
        return serializers.FunctionsSerializer

    def get(self, request, *args, **kwargs):
        id = request.GET.get("id", None)
        if id:
            result = []
            self.queryset = models.Function.objects.filter(parent_id=id, is_active=True)
            for query in self.queryset:
                data = serializers.FunctionsSerializer(query).data
                if models.Function.objects.filter(parent_id=data["id"], is_active=True):
                    data.setdefault("have_child", True)
                else:
                    data.setdefault("have_child", False)
                result.append(data)
            return Response(result, status=status_code.HTTP_200_OK)
        return super(FunctionsView, self).get(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)


class FunctionView(mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   generics.ListAPIView):
    """
    按URL中的Function ID獲取單條Function的信息，支持刪、改的操作
    """
    def get_serializer_class(self):
        return serializers.FunctionSerializer

    def get_queryset(self):
        return models.Function.objects.all()

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

    def get(self, request, *args, **kwargs):
        func = self.get_object()
        data = serializers.FunctionSerializer(func).data
        return Response(data)


class RoleFunctionsMapView(generics.ListCreateAPIView):
    """
    Role functions\n
    參數一：'role'是單個的數字類型（角色ID）\n
    參數二：'function'是功能ID的數組類型，即使只有一個功能，也需要是數組
    """
    serializer_class = serializers.RoleFunctionSerializer
    queryset = models.RoleFunctionMap.objects.all()

    def post(self, request, *args, **kwargs):
        data = tools.is_valid(request, "POST", role=None, function=None)
        if not isinstance(data, dict):
            return data
        RoleObj = ars.Role(data["role"], data["function"])
        result = RoleObj.add_role_function()
        return Response({"message": result}, status=status_code.HTTP_201_CREATED)
        # return super(RoleFunctionsMapView, self).post(request, *args, **kwargs)


class RoleFunctionMapView(mixins.RetrieveModelMixin,
                          mixins.UpdateModelMixin,
                          mixins.DestroyModelMixin,
                          generics.ListAPIView):
    """
    Role function
    """
    serializer_class = serializers.RoleFunctionSerializer
    queryset = models.RoleFunctionMap.objects.all()

    def get(self, request, *args, **kwargs):
        self.queryset = self.get_object()
        return Response(self.serializer_class(self.queryset).data, status=status_code.HTTP_200_OK)

    def put(self, request, *args, **kwargs):
        data = tools.is_valid(request, "PUT", "role.func_list")
        if not isinstance(data, dict):
            return data
        obj = self.get_object()
        RoleObj = ars.Role(obj.role_id, data["role.func_list"])
        try:
            result = RoleObj.update_role_function()

            # 当角色的功能发生变更时，通知所有与此角色相关的用户刷新菜单
            userID = self.get_object().role.UR_role.all().values_list("user_id", flat=True)
            updateMenu(userID)

            return Response({"status": "True", "msg": result})
        except Exception as error:
            return Response({"status": "False", "msg": str(error)})
        # return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):

        # 当角色的功能发生变更时，通知所有与此角色相关的用户刷新菜单
        userID = self.get_object().role.UR_role.all().values_list("user_id", flat=True)
        updateMenu(userID)

        return self.delete(request, *args, **kwargs)


class BulkAddFunctionView(generics.ListAPIView):
    """
    批量添加功能至角色接口 \n
    1、GET：传入一个功能ID参数，如'?function=12'，返回包含这个功能的角色列表 \n
    2、POST：传入两个参数，分别为functions功能ID列表，roles角色ID列表
    """
    serializer_class = serializers.BulkAddFunctionSerializer

    def get_queryset(self):
        pass

    def get(self, request, *args, **kwargs):
        function = request.GET.get("function", None)

        if function:
            maps = models.RoleFunctionMap.objects.filter(function_id=function).values("role_id")
            roles = [map["role_id"] for map in maps]
            return Response({"status": "True", "data": roles})
        else:
            return Response({"status": "False", "msg": "Value error!"})

    def post(self, request, *args, **kwargs):
        data = tools.is_valid(request, "POST", "functions", "roles")
        if not isinstance(data, dict):
            return data

        functions = tools.list_str_to_int(eval(data["functions"]))
        roles = tools.list_str_to_int(eval(data["roles"]))

        for function in functions:                  # 检查是否需要删除
            maps = models.RoleFunctionMap.objects.filter(function_id=function)
            old_role = {}
            for map in maps:                        # 存好该模块对应的旧角色有哪些
                old_role[map.role_id] = map
            del_roles = list(set(old_role.keys()).difference(set(roles)))       # 比对新角色列表，得到需要删除的角色ID
            for del_role in del_roles:              # 通过需要删除的角色ID取出map关系对象，执行删除
                old_role[del_role].delete()

        result = {"succeed": [], "error": []}

        for role in roles:                          # 执行添加角色和功能的映射关系
            role_update = ars.Role(role, functions)
            try:
                result["succeed"].append(role_update.add_role_function())
            except Exception as error:
                result["error"].append(str(error))

        return Response({"status": "True", "result": result})
